<?php

class XMLParser {
	private static $parser = null;
	private static $struct = array();
	private static $index = array();


	public static function parseFile($filename) {
		return self::parse(file_get_contents($filename));
	}

	public static function parse($xmlstr) {
		self::$parser = xml_parser_create('UTF-8');
		xml_parser_set_option(self::$parser,XML_OPTION_CASE_FOLDING,0);
		xml_parse_into_struct(self::$parser,$xmlstr,self::$struct,self::$index);
		xml_parser_free(self::$parser);

		$name = self::$struct[0]['tag'];
		$array[$name] = isset(self::$struct[0]['attributes']) ? self::$struct[0]['attributes'] : '';
		$array[$name] = self::struct2array(self::$struct);

		return $array;
	}

	private static function struct2array($values, &$i = 0) {
		$child = array();
		if (trim($values[$i]['value'])) array_push($child, $values[$i]['value']);

		while ($i++ < sizeof($values)) {
			switch ($values[$i]['type']) {
				case 'cdata':
					break;
				case 'complete':
					$name = $values[$i]['tag'];
					if(!empty($name)){
						$child[$name] = $values[$i]['value']? $values[$i]['value'] : '';
						if(isset($values[$i]['attributes'])) {
							$child[$name] = $values[$i]['attributes'];
						}
					}
					break;
				case 'open':
					$name = $values[$i]['tag'];
					$child[$name] = self::struct2array($values, $i);
					break;

				case 'close':
					return $child;
					break;
			}
		}
		return $child[0];
	}

	public static function array2xml($array, $encoding = 'UTF-8') {
		$ret = '<?xml version="1.0" encoding="'.$encoding.'"?>';
		$ret .= self::_2xml($array);
		return $ret;
	}
	private static function _2xml($array, $level = 0) {
		$ret = '';
		foreach ($array as $key => $value) {
			if (is_string($value) && (strpos($value,'<')!==false && strpos($value,'>') !== false)) {
				$cdataS = '<![CDATA[';
				$cdataE = ']]>';
			} else {
				$cdataS = '';
				$cdataE = '';
			}
			if (is_numeric($key) ){
				$ret .= self::_2xml($value,$level + 1);
			} else if (is_array($value)) {
				$ret .= "\r\n".str_repeat("\t",$level) . '<'.$key.'>';
				$ret .= self::_2xml($value,$level + 1);
				$ret .= "\r\n".str_repeat("\t",$level) . '</'.$key.'>';
			} else {
				$ret .= "\r\n".str_repeat("\t",$level) . '<'.$key.'>'.$cdataS.$value.$cdataE.'</'.$key.'>';
			}
		}
		return $ret;
	}
}
